*******************************************************************************
* Jiffy Windows - Pixel Transfer Demonstration
*
* (C)  Copyright Apple Computer, Inc. 1988
* All rights reserved.
*
* by Keith Rollin
* September 1, 1988
*
* This program shows the use of PPToPort and OffScreen GrafPorts in
* the implementation of a window content caching system. It presents 5 "Test"
* windows and a large window full of text to show the effects of this caching.
*
* Caching is setup at the time the window is created and performed the first
* time the window needs to be updated (drawn). Before the window is created,
* a routine (AddCacheRecord) is called to create a "Cache Record". The handle
* to this cache record is stored in the window's RefCon, and contains infor-
* mation on the offscreen image. When it comes time to draw to the screen, this
* record is examined to see if there is any information buffered already. If
* not, then drawing occurs to the offscreen buffer. After an offscreen image
* has been made, updates are performed by calling PPToPort to copy the image
* from the offscreen buffer to the screen. If, for any reason, an offscreen
* buffer cannot be made, drawing occurs to the window directly.
*
* An effort has been made to make this caching as transparent as possible.
* Windows act normally, and the routines that update them in a normal envi-
* ronment can be used in this buffered environment. The caching routine is
* inserted in between TaskMaster and the update routine, and calls the update
* routine almost as if it were called by TaskMaster. The only difference is
* that the routine is drawing to an offscreen GrafPort, and not a Window
* record.
*
*
* Files:	System macros and equates.
*	Jiffy.stds.aii
*
*
* Modification History:
*
* Version 1.0	Rollin
*
*      September 1, 1988
*
*      First Release
*
*******************************************************************************
	eject
	
**********************************************************************
*                                                                    *
*             Apple IIGS Source Code Sampler, Volume I               *
*                                                                    *
*             Copyright (c) Apple Computer, Inc. 1988                *
*                       All Rights Reserved                          *
*                                                                    *
*            Written by Apple II Developer Tech Support              *
*                                                                    *
*                                                                    *
*                                                                    *
*  ----------------------------------------------------------------  *
*                                                                    *
*     This program and its derivatives are licensed only for         *
*     use on Apple computers.                                        *
*                                                                    *
*     Works based on this program must contain and                   *
*     conspicuously display this notice.                             *
*                                                                    *
*     This software is provided for your evaluation and to           *
*     assist you in developing software for the Apple IIGS           *
*     computer.                                                      *
*                                                                    *
*     DISCLAIMER OF WARRANTY                                         *
*                                                                    *
*     THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                       *
*     WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,               *
*     WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
*     FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
*     THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH            *
*     YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND            *
*     NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)               *
*     ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,             *
*     REPAIR OR CORRECTION.                                          *
*                                                                    *
*     Apple does not warrant that the functions                      *
*     contained in the Software will meet your requirements          *
*     or that the operation of the Software will be                  *
*     uninterrupted or error free or that defects in the             *
*     Software will be corrected.                                    *
*                                                                    *
*     SOME STATES DO NOT ALLOW THE EXCLUSION                         *
*     OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY              *
*     NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC            *
*     LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS                *
*     WHICH VARY FROM STATE TO STATE.                                *
*                                                                    *
*                                                                    *
**********************************************************************
	eject
	
	PRINT NOGEN,NOHDR

	STRING ASIS

	PRINT PUSH,OFF
	INCLUDE 'M16.Util'
	INCLUDE 'M16.ProDOS'
	INCLUDE 'M16.MiscTool'
	INCLUDE 'M16.QUICKDRAW'
	INCLUDE 'E16.Quickdraw'
	INCLUDE 'M16.QDAux'
	INCLUDE 'M16.MEMORY'
	INCLUDE 'E16.Memory'
	INCLUDE 'M16.EVENT'
	INCLUDE 'E16.EVENT'
	INCLUDE 'M16.LOCATOR'
	INCLUDE 'M16.Menu'
	INCLUDE 'M16.Control'
	INCLUDE 'M16.Window'
	INCLUDE 'E16.Window'
	INCLUDE 'M16.Dialog'
	INCLUDE 'E16.Dialog'
	INCLUDE 'M16.LineEdit'
	INCLUDE 'M16.IntMath'
	INCLUDE 'M16.Scrap'
	INCLUDE 'M16.Desk'
	INCLUDE 'M16.Texttool'
	INCLUDE 'M16.Font'
	PRINT POP

*******************************************************************************
*
*    Equates used in this program.
*
*******************************************************************************
DPHandle	equ 0	; Handle to Tool Direct Page area
DPPointer	equ DPHandle+4	; Pointer to Tool Direct Page area
deref	equ DPPointer+4	; Temporary Handle dereference area
CPPtr	equ Deref+4	; pointer to current caching parms
Temp1	equ CPPtr+4	; temp pointer
Temp2	equ Temp1+4	; temp pointer

ScreenMode	equ Mode640
ScreenWidth	equ 640

CacheRecordSize	equ 12

	EJECT
*******************************************************************************
*
Main	PROC
*
* Description:	This is the main routine. It calls routines to Initialize
*	the tools, initialize application specific data, run the
*	main EventLoop, close the application, and close the tools.
*	Then it calls the ProDOS Quit command.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import InitTools
	import InitApp
	import EventLoop
	import CloseApp
	import CloseTools
	import QuitParms
*
* Entry Points:	NONE
*
*******************************************************************************

	jsr InitTools
	jsr InitApp

	_ShowCursor

	jsr EventLoop

	jsr CloseApp
	jsr CloseTools

	_Quit QuitParms

	ENDP

	EJECT
*******************************************************************************
*
Globals	Record
*
* Description:	Holder of all of our data.
*
*
* Inputs:	N/A
*
* Outputs:	N/A
*
* External Refs:
	import DrawOdyRtn
	import CacheContent
	import DrawContent
*
* Entry Points:
	export QuitParms	; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString	str 'Jiffy Windows'
AutString	str 'By Keith Rollin, Apple II DTS'
CopyString	str '©1988 Apple Computer'
VerString	str 'Version 1.0        September 1, 1988'
AboutData	dc.b '73/*0',13,'*1',13,'*2',13,'*3/^#0',0
SubStrings	dc.l TitleString,AutString,CopyString,VerString

MenuHeight	ds.B 2	; Stored height of menu bar
MyID	ds.B 2	; Application ID
MyDP	ds.B 2	; My direct page storage

QuitFlag	ds.W 1
QuitParms	dc.L 0	; Pathname of next app
	dc.W $00	; flags

EventRecord
EventWhat	ds.B 2
EventMessage	ds.B 4
EventWhen	ds.B 4
EventWhere	ds.B 4
EventModifiers	ds.B 2
TaskData	ds.B 4
TaskMask	dC.L $0000FFFF

	EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr	dc.l AppMenu
	dc.l FileMenu
	dc.l EditMenu
MenuPtrLen	equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.

AppMenu	dc.B '$$@\N1',$0D
	dc.B '--About Jiffy Windows...\N256V',0
	dc.B '.'
FileMenu	dc.B '$$  File  \N2',0
	dc.b '--Open Test Windows\N258',0
	dc.B '--Read a book\N259',0
	dc.B '--Close\N255DV',0
	dc.B '--Quit\N257*Qq',0
	dc.B '.'
EditMenu	dc.B '$$  Edit  \N3',0
	dc.B '--Undo\N250*ZzVD',0
	dc.B '--Cut\N251*XxD',0
	dc.B '--Copy\N252*CcD',0
	dc.B '--Paste\N253*VvD',0
	dc.B '--Clear\N254D',0
	dc.B '.'

wPtr1	dc.l 0
wPtr2	dc.l 0
wPtr3	dc.l 0
wPtr4	dc.l 0
wPtr5	dc.l 0
OdyWindow	dc.l 0

WindowTitle1	str '  Window 1 (not Cached)  '
WindowTitle2	str '  Window 2 (not Cached)  '
WindowTitle3	str '  Window 3 (Cached)  '
WindowTitle4	str '  Window 4 (Cached)  '
WindowTitle5	str '  Window 5 (Cached)  '

wtPtrs	dc.l WindowTitle1,WindowTitle2,WindowTitle3,WindowTitle4,WindowTitle5

Stripes
	DC.W $0000	; Black frame
	DC.W $0f00	; Inact TBcolor, Inact TColor, Tcolor
	DC.W $020f	; Pattern, Pattern color, BG color
	DC.W $0000	; Frame growbox unselcted/selected
	DC.W $00f0	; infobar color (white)

MWindData	DC.W MWEnd-MWindData
	DC.W fTitle+fClose+fMove
WindowTitle	DC.L 0	; Ptr to title
	DC.L 0	; RefCon
	DC.W 0,0,0,0	; Full Size (0= default)
	DC.L stripes	; Color Table Pointer
	DC.W 0,0	; Vertical/Horizontal origin
	DC.W 0,0	; Data area height, width
	DC.W 0,0	; Max Cont height, width
	DC.W 0,0	; Pixels to scroll vert'ly, horiz'ly
	DC.W 0,0	; Pixels to page vert'ly, horiz'ly
	DC.L 0	; Information bar refcon.
	DC.W 0	; Info bar height
	DC.L 0	; DefProc.
	DC.L 0	; Routine to draw info. bar.
contDraw	DC.L CacheContent	; Routine to cache/draw content.
wPosition	DC.W 10,40,120,400	; Size and position
	DC.L $FFFFFFFF	; Plane to put window up in (bottommost).
	DC.L 0	; Address for window record (0 to alloc)
MWEnd
;
; These parms MUST follow immediately after the window record
;
MWCacheParms	dc.l DrawContent-1	; real draw routine
	dc.l 0	; space for caching handle
	dc.w 110,360	; Height, width


OdyTitle	str '  Odyssey  '
OdyWindData	DC.W OdyEnd-OdyWindData
	DC.W fTitle+fClose+fMove+fRScroll+fBScroll+fGrow
	DC.L OdyTitle	; Ptr to title
	DC.L 0	; RefCon
	DC.W 0,0,0,0	; Full Size (0= default)
	DC.L stripes	; Color Table Pointer
	DC.W 0,0	; Vertical/Horizontal origin
	DC.W 797,600	; Data area height, width
	DC.W 0,0	; Max Cont height, width
	DC.W 32,32	; Pixels to scroll vert'ly, horiz'ly
	DC.W 0,0	; Pixels to page vert'ly, horiz'ly
	DC.L 0	; Information bar refcon.
	DC.W 0	; Info bar height
	DC.L 0	; DefProc.
	DC.L 0	; Routine to draw info. bar.
	DC.L CacheContent	; Routine to cache/draw content.
	DC.W 30,5,185,605	; Size and position
	DC.L $FFFFFFFF	; Plane to put window up in (bottommost).
	DC.L 0	; Address for window record (0 to alloc)
OdyEnd
;
; These parms MUST follow immediately after the window record
;
OdyCacheParms	dc.l DrawOdyRtn-1
	dc.l 0	; space for caching handle
	dc.w 792,640	; Height, width

Odyssey
	dc.b 13,13
	dc.b 1,'J',1,0
	dc.b 1,'F',0,0,0,16	; Shaston 16
	dc.b '1',13
	dc.b 'Boot Camp',13
	dc.b 1,'J',2,0
	dc.b 1,'F',0,0,0,8	; Shaston 8
	dc.b 13,13
	dc.b '      At Pepsi, we lived for the smallest details.'
	dc.b 13,13
	dc.b '     The moment I entered the boardroom, I knew the '
	dc.b 'meeting would be momentous. For years, these '
	dc.b 'executive sessions had followed a carefully '
	dc.b 'orchestrated ritual. Today, there was a subtle, '
	dc.b 'though telling, difference.',13,13

	dc.b '     Ordinarily, the conference table''s 21-foot-'
	dc.b 'long surface, polished to look more like glass than '
	dc.b 'the rare burl of Carpathian elm, would be touched '
	dc.b 'only by PepsiCo board members, and then no more '
	dc.b 'than twelve times a year. Today, the fitted leather '
	dc.b 'covering that hid the gleaming top was removed.'
	dc.b 13,13

	dc.b '     I had been in this room at least a hundred '
	dc.b 'times. I had sat worried at this table and I had '
	dc.b 'nearly soared at it. I had witnessed tense '
	dc.b 'colleagues - friends - being publicly hung for '
	dc.b 'questions of performance, and I had seen them '
	dc.b 'applauded, just as I had been here, for marketing '
	dc.b 'ideas and strategies.',13,13

	dc.b '     But this meeting was different. the table''s '
	dc.b 'exposed top said so. It made the spacious, '
	dc.b 'windowless room all the more imposing. Like nearly '
	dc.b 'everything else at PepsiCo, Inc., the room''s '
	dc.b 'stately power and elegance made you stand a little '
	dc.b 'straighter. A large abstact painting by Jackson '
	dc.b 'Pollock''s widow, Lee Krasner, dominated the far '
	dc.b 'wall. Custom-designed carpeting in earth-tone '
	dc.b 'colors cushioned the floor. The bronze-plated '
	dc.b 'ceiling, perhaps more appropriate for a church, '
	dc.b 'reflected burnished mahogany-paneled walls. High-'
	dc.b 'backed beige leather chairs, so imposing they could '
	dc.b 'have carried corporate titles of their own, '
	dc.b 'surrounded the boardroom table.',13,13

	dc.b '     Every two months the marketing gurus of Pepsi '
	dc.b '-- the company''s heart and soul -- would gather '
	dc.b 'here, on 4/3, the executive floor of PepsiCo''s '
	dc.b 'corporate headquarters in the New York City suburb '
	dc.b 'of Purchase, for a private ritual in the public war '
	dc.b 'on the colas between Pepsi and Coke. A. C. Neilsen '
	dc.b 'Co., the country''s most prestigious market-'
	dc.b 'research firm, would formally present what became '
	dc.b 'popularly known as the Nielsens -- closely guarded '
	dc.b 'market-share figures that showed how we were faring '
	dc.b 'in our competitive battle with Coca-Cola Co. The '
	dc.b 'Nielsens defined the ground rules of competition '
	dc.b 'for everyone at Pepsi. They were at the epicenter '
	dc.b 'of all we did. They were the non-public body counts '
	dc.b 'of the Cola Wars.',13,13

	dc.b '     Like the other meetings, this one was a '
	dc.b 'ceremonial event. We marked it on our calendars '
	dc.b 'many weeks in advance. Everyone wore the unofficial '
	dc.b 'corporate uniform: a blue pin-striped suit, white '
	dc.b 'shirt, and a sincere red tie. None of us would ever '
	dc.b 'remove his jacket. We dressed and acted as if we '
	dc.b 'were at a meeting of the board of directors.',13,13

	dc.b '     The Nielsen executives were the first to '
	dc.b 'arrive. They carried themselves like accountants -- '
	dc.b 'good presenters with bland personalities in blue '
	dc.b 'and gray suits. They were followed by Pepsi''s '
	dc.b 'junior executives, the support staff of market '
	dc.b 'researchers and brand managers who could provide a '
	dc.b 'stray fact of figure for the division officers and '
	dc.b 'vice presidents who filed into the room next.',13,13

	dc.b '     Everyone in this room was on the fast track, '
	dc.b 'which at Pepsi was more like a racecourse.The '
	dc.b 'senior officers here were the best of the best. In '
	dc.b 'a corporation populated with bright, ambitious '
	dc.b 'achievers, they were peerless. They had proven they '
	dc.b 'were intellectually and physically fit supervisors '
	dc.b 'in America''s corporate Marine Corps.',13,13

	dc.b '     As president of Pepsi-Cola, I entered the room '
	dc.b 'next. Corporate formality dictated where all of us '
	dc.b 'sat. The company''s top officers gravitated to the '
	dc.b 'front of the table, the junior execs toward the '
	dc.b 'back. Staff people found chairs away from the table '
	dc.b 'along the walls. When everyone was in place, I went '
	dc.b 'across the hall to alert PepsiCo''s president, '
	dc.b 'Andrall E. Pearson, who then joined us.',13,13
	
	dc.b '     Everyone chatted away until the heavy wooden '
	dc.b 'doors opened once again. The room fell quiet as a '
	dc.b 'big-boned man with a frizzy shock of white hair '
	dc.b 'strode in. PepsiCo chairman and chief executive '
	dc.b 'Donald M. Kendall, fifty-seven, was no taller than '
	dc.b 'six feet one, but he was a man of enormous '
	dc.b 'presence, respected and feared by colleagues. '
	dc.b 'Today, Kendall was feeling great pleasure. He '
	dc.b 'worked the room like a politician, gripping hands, '
	dc.b 'slapping backs, and giving an occasional bear hug '
	dc.b '-- a patented gesture of strength and affection '
	dc.b 'that Kendall reserved for only a few.',13,13
	dc.b 'From Odyssey by John Sculley',13
	dc.b 'Used by Permission, Harper & Row, Publishers, Inc.'
	dc.b 13,13
OdysseyEnd
	ENDR

	EJECT
*******************************************************************************
*
InitApp	PROC
*
* Description:	Perform any application specific initialization.
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import SlowDraw
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	stz QuitFlag

;
; Create 5 test windows. Loop from 4 to 0, calling AddWindow with
; the loop index in the accumulator. AddWindow will use this index
; to name the window, determine if it should be cached or not, and
; stagger its position.
;

	lda #4
	sta Windex
loop	lda Windex
	jsr AddWindow
	dec Windex
	bpl loop


;
; Create the window to hold John "The Dude" Sculley's book.
;
	lda #odyWindData	; create a cache record for it
	ldx #^OdyWindData
	jsr AddCacheRecord

	pha
	pha
	PushLong #OdyWindData
	_NewWindow
	PullLong OdyWindow

	rts

Windex	ds.b 2

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Enter this routine with an index from 0 to 4. This index is
; used to set the window's title from a list of titles, stagger
; its position and to determine whether or not it should be cached.
;

AddWindow

;
; Turn the window counter into an array index. This index is
; stored in X and is used throughout the routine, so I need
; to be sure not to destroy it!
;
	asl a
	asl a
	tax
	stx IndexSave
;
; Set up the pointer to the window's name
;
	lda wtPtrs,x
	sta WindowTitle
	lda wtPtrs+2,x
	sta WindowTitle+2

; Bump the window's position so as to stagger them

	ldy #6
loop2	lda wPosition,y
	clc
	adc #20
	sta wPosition,y
	dey
	dey
	bpl loop2

; the last 2 windows are special...they don't get cached...

	cpx #4
	bne CreateIt
	lda #SlowDraw
	sta ContDraw
	lda #^SlowDraw
	sta ContDraw+2

CreateIt
	lda #MWindData	; create a cache record for it
	ldx #^MWindData
	jsr AddCacheRecord

	pha
	pha
	PushLong #MWindData
	_NewWindow

	ldx IndexSave
	lda 1,s
	sta wPtr1,x	; now save our window pointer in our
	lda 3,s	; window pointer array.
	sta wPtr1+2,x
;
; the window pointer is still on the stack, so use it to
; set the current port (NewWindow doesn't do that!!!)
;
	_SetPort

done
	rts

IndexSave	ds.b 2

;
; Just before creating a new window, we must create a cache record for it.
; This record will hold: a) the routine to draw the contents the first time,
; b) a pointer to the offscreen GrafPort, and c) the dimensions needed to
; create the GrafPort. This cache record is created from a template stored
; IMMEDIATELY after the window parameter list (after owStorage).
;
; Enter this routine with the pointer to the window parameter list in A,X.
;
AddCacheRecord
	sta temp1
	stx temp1+2	; temp1 now points to the parmlist

	clc	; make a pointer to the template
	adc #owStorage+4
	sta temp2
	stx temp2+2

	pha	; space for the new handle
	pha
	PushLong #CacheRecordSize
	PushWord MyID
	PushWord #attrNoCross
	PushLong #$0000
	_NewHandle
	PullLong myHandle	; handle to cache record in deref

	PushLong Temp2	; copy the template over
	PushLong myHandle
	PushLong #CacheRecordSize
	_PtrToHand

	ldy #owRefCon	; set the RefCon to the handle
	lda myHandle
	sta [temp1],y
	iny
	iny
	lda myHandle+2
	sta [temp1],y

	rts

myHandle	ds.b 4

	ENDP

	EJECT
*******************************************************************************
*
CloseApp	PROC
*
* Description:	Close down things. This disposes of all items and memory
*	that we allocated.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

; Sly Trick #1!!! Traverse the window list, clearing the visible
; bit in each one. Then, when the window manager closes down, it
; will think that all windows are hidden, and it will NOT erase
; them from the screen. This makes quitting faster!

	pha	; get a pointer to the first
	pha	; window.
	_GetFirstWindow
	PullLong Temp1

loop
	pha	; get the window's bit flags
	PushLong Temp1
	_GetWFrame
	pla

	and #$FFFF-fVis	; turn off the Vis Flag

	pha	; now send it back out
	PushLong Temp1
	_SetWFrame

	pha	; get the next window in the
	pha	; list
	PushLong Temp1
	_GetNextWindow
	PullLong Temp1

	lda Temp1	; If NULL ($0000 0000) was returned
	bne loop	; then we are out to windows to
	lda Temp1+2	; fix.
	bne loop

	rts
	ENDP

	EJECT
*******************************************************************************
*
EventLoop	PROC
*
* Description:	Main Event Loop. Handle things until user selects Quit.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import MenuSelect
	import ignore
	import doUpdate
	import doClose
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	pha	; Push on space for TaskMaster result
	PushWord #EveryEvent ; GetNextEvent mask
	PushLong #EventRecord ; Pointer to Event Record
	_TaskMaster

	pla	; Get TaskMaster result
	beq EventLoop	; Remove if you want to use null events
	asl A	; Turn it into an index
	tax
	jsr (TaskTable,x)	; Call appropriate event handler

	lda QuitFlag	; Quit selected?
	beq EventLoop	; no - keep looping

	rts	; yes- leave the program

TaskTable	dc.W Ignore	; 0 Null
	dc.W Ignore	; 1 MouseDown
	dc.W Ignore	; 2 MouseUp
	dc.W Ignore	; 3 KeyDown
	dc.W Ignore	; 4 undefined
	dc.W Ignore	; 5 AutoKey
	dc.W Ignore	; 6 Update
	dc.W Ignore	; 7 undefined
	dc.W Ignore	; 8 Activate
	dc.W Ignore	; 9 Switch
	dc.W Ignore	; 10 Desk accessory
	dc.W Ignore	; 11 Device driver
	dc.W Ignore	; 12 ap
	dc.W Ignore	; 13 ap
	dc.W Ignore	; 14 ap
	dc.W Ignore	; 15 ap
	dc.W Ignore	; TASK 0 indesk
	dc.W MenuSelect	; TASK 1 in menuBar
	dc.W Ignore	; TASK 2 in system window
	dc.W Ignore	; TASK 3 in content
	dc.W Ignore	; TASK 4 in Drag
	dc.W Ignore	; TASK 5 in grow
	dc.W DoClose	; TASK 6 in goaway
	dc.W Ignore	; TASK 7 in zoom
	dc.W Ignore	; TASK 8 in info bar
	dc.W MenuSelect	; TASK 9 in special menu
	dc.W Ignore	; TASK 10 in NDA
	dc.W Ignore	; TASK 11 in frame
	dc.W Ignore	; TASK 12 in drop

	ENDP

	EJECT
*******************************************************************************
*
MenuSelect	PROC
*
* Description:	This routine is called when TaskMaster returns a menu
*	event. It takes the menu item that was hit and calculates
*	an offset into the menu dispatch table. It then calls that
*	routine and unhilites the menu when it is done.
*
* Inputs:	TaskData holds menu item selected.
*
* Outputs:	NONE
*
* External Refs:
	import ignore
	import doClose
	import doAbout
	import doQuit
	import doOpenTest
	import doShowOdy
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda TaskData	; Get the ID of the menu item selected.
	sec	; Turn it into an index by subtracting
	sbc #250	; the starting ID number (25) and mul-
	asl a	; tiplying by 2 (each table entry con-
	tax	; sists of 2 bytes).
	jsr (menuTable,x)	; Call the routine behind it.

	PushWord #0	; Routine done - unhilite the menubar.
	PushWord taskData+2
	_HiLiteMenu

	rts

MenuTable	dc.W Ignore	; undo
	dc.W Ignore	; cut
	dc.W Ignore	; copy
	dc.W Ignore	; paste
	dc.W Ignore	; clear
	dc.W doclose	; close
	dc.W doAbout
	dc.W doQuit
	dc.W DoOpenTest	; open 5 windows with stuff in them
	dc.W DoShowOdy	; purge the refcons
	ENDP

	EJECT
*******************************************************************************
*
Ignore	PROC
*
* Description:	Called when I want to ignore an event.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************

	rts
	ENDP

	EJECT
*******************************************************************************
*
doAbout	PROC
*
* Description:	Bring up an Alert Dialog box with our name in it. This
*	uses the new _AlertWindow call implemented in the Window
*	Manager on System Disk 3.2.
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	pha	; space for result
	PushWord #1	; we are using P-Strings
	PushLong #SubStrings
	PushLong #AboutData
	ldx #$590E	; _AlertWindow
	jsl $E10000
	pla	; pull off button hit

	rts

	EJECT
*******************************************************************************
*
DoOpenTest	PROC
*
* Description:	Open the 5 test windows that we created in InitApp. It
*	merely loops through an array of 5 window pointers and
*	calls SelectWindow and ShowWindow for all of them. It then
*	disables the menu item that was used to call this routine
*	and enables the Close menu Item.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda #4	; we need to count through 5 windows
loop
	pha	; save the counter on the stack
	asl a	; turn it into an index
	asl a
	tax
	lda wPtr1+2,x	; get a window pointer from my array
	tay	; of test windows.
	lda wPtr1,x

	phy	; push on window ptr for _SelectWindow
	pha
	phy	; push on window ptr for _ShowWindow
	pha

	_SelectWindow	; Bring the window to front
	_ShowWindow	; Make it visible

	pla	; get my counter back
	dec a	; loop down to the next window.
	bpl loop	; if >= 0 keep looping

	PushWord #258	; Disable "Open Test Windows" item
	_DisableMItem

	PushWord #255	; windows are open, enable close item
	_EnableMItem

	rts
	ENDP

	EJECT
*******************************************************************************
*
DoShowOdy	PROC
*
* Description:	Show the window that displays the first few pages of John
*	Buddy's book. This routine Selects the window, and then
*	Shows it to make it visible. It finishes up by disabling
*	the Read a Book menu item and enabling the Close item.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushLong OdyWindow
	_SelectWindow

	PushLong OdyWindow
	_ShowWindow

	PushWord #255	; windows are open - enable close item
	_EnableMItem

	PushWord #259	; Disable "Read Book" item
	_DisableMItem

	rts
	ENDP

	EJECT
*******************************************************************************
*
DoClose	PROC
*
* Description:	Closes the top window by hiding it. If it closes the last
*	window on the screen, the Close menu item is disabled.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

; While closing the window, we have to get a little tricky. If we are closing
; the Odyssey window, then we have to enable the "Read a Book" menu item. If
; we are closing any of the Test window, we have to enable the "Open Test
; Windows" menu item. We perform this check by getting the pointer to the top
; window, and comparing it to the stored pointer to the Odyssey window. If they
; match, then we know we are closing the Odyssey window. If not, then we assume
; that we are closing a Test window. We don't have to worry about NDA windows
; getting in the way as those are taken care of TaskMaster before we ever get
; here.
;

	pha	; get the front window
	pha
	_FrontWindow

	stz WindType	; Assume we're closing a test window.

	lda 1,s	; Check to see if we are closing
	cmp OdyWindow	; the Odyssey window
	bne HideIt
	lda 3,s
	cmp OdyWindow+2
	bne HideIt

	inc WindType	; set flag to say we closed Odyssey
HideIt
	_HideWindow	; hide the top window

	lda WindType	; did we close a test window?
	bne EnableOdy 	; no, enable "Read a Book"

	PushWord #258	; yes, so re-enable that menu item
	_EnableMItem	; to let us re-open it.
	bra CheckForMoreWindows

EnableOdy
	PushWord #259	; re-enable Read A Book menu item
	_EnableMItem	; to let us re-open it.

CheckForMoreWindows
	pha	; any more front windows?
	pha
	_FrontWindow

	plx
	pla
	bne done	; yes, so leave
	txa
	bne done	; yes, so leave

	PushWord #255	; no, so disable close item
	_DisableMItem

done
	rts
WindType	ds.b 2
	ENDP

*******************************************************************************
*
CacheContent	PROC
*
* Description:	This routine draws the contents of the window. Since it
*	is called from TaskMaster, we need to set the Direct Page
*	and Data Bank registers. The we prepare to draw the window.
*	First we check to see if there is a handle in the window's
*	RefCon, and make sure that it is not purged. If it is
*	still valid, it is used to update the window. If not, then
*	the window is drawn by hand.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import GetOffScreenBuffer
	import DrawByHand
*
* Entry Points:
	export oldPort	; used by DrawByHand
*
*******************************************************************************
	With Globals

;
; CacheContents is called from the Window Manager to update the contents
; of the window. Therefore, the Direct Page and Data Bank Register may
; not be set to what our application had them set to. Save the settings
; as the Window Manager had them, and then set them up the way we like
; them. That way we can use local (2-byte absolute) addressing, and can
; access our Direct Page variables.

	phd	; Save caller's direct page
	phb	; Save caller's data bank register

	phk	; switch data bank to Program Bank
	plb
	lda MyDP	; switch Direct Page to application's
	tcd

SetUp

; Get the port of the window that we have to update

	pha	; space for result of GetWRefCon
	pha
	pha	; space for result of GetPort
	pha
	_GetPort

	lda 1,s	; save the current port for later
	sta oldPort	; when we leave this routine. the port
	lda 3,s	; gets changed if we have to draw into
	sta oldPort+2	; the offscreen buffer.

	_GetWRefCon	; Get refcon, which holds a handle to
	PullLong Deref	;   the cache record.

	ldy #4	; Lock the handle to the cache record.
	lda [deref],y	; We do this using the method documented
	ora #attrLocked	; in the description of HLock in the
	sta [deref],y	; memory manager chapter.
	dey
	dey
	lda [deref],y	; dereference it. Get a pointer to the
	sta CPPtr+2	; cache record.
	lda [deref]
	sta CPPtr

	ldy #4	; See if we have cached the contents.
	lda [CPPtr],y	; We determine this by seeing if the
	iny	; pointer is a NULL pointer.
	iny
	ora [CPPtr],y	; see if the pointer is $0000 0000
	bne haveBuffer	; no it's not, so update from offscreen

; We don't have an offscreen buffer, so this is what we are going to do. First
; save the old port (the window that we are updating). Then, try to get an
; offscreen GrafPort for buffering. If that is successful, then the port will
; be set to it. Regardless of the outcome, however, we will draw the entire
; contents to whatever is active. Then we check the status of the
; GetOffScreenBuffer call. If it succeeded, then copy the buffer's contents
; to the window. If it didn't then what we drew appeared on the screen anyway,
; and we're done.


	lda oldPort	; pass the window pointer in X & Y
	ldx oldPort+2
	jsr GetOffScreenBuffer ; changes the port if successful
	php	; save the status of this call
	jsl DrawByHand	; draw the contents to cache or screen

	PushLong oldPort	; reset the port to window port
	_SetPort

	plp	; Did offscreen caching occur?
	bcc SetUp	; yes - now try again
	bcs done	; no - we drew to screen - so exit.

haveBuffer
;
; We have an offscreen buffer. Prepare the stack for a PPToPort call.
;
	ldy #6	; push on source LocInfo pointer
	PushWord [CPPtr],y	; This pointer points to the LocInfo
	dey	; of the OffScreen buffer, and is
	dey	; stored in the Cached Record.
	PushWord [CPPtr],y

;
; We push on a pointer to VisRect here, but haven't yet initialized it! But
; don't worry. We will fill in VisRect down below.
;
	PushLong #VisRect	; pass the pointer to the visrect.

	lda oldPort	; get the pointer to the dest port.
	sta deref
	lda oldPort+2
	sta deref+2

; Now we need to tell PPToPort what part of the screen to update. This is
; done by looking at the VisRgn (which contains the intersection of the
; update region and the VisRgn). The format of a region is:
;
;  WORD: rgnSize  Size of the region
;  RECT: rgnBBox  rectangle the just surrounds the region
;  XXXX: rgnData  region data the would get me fired if I told you what it was.
;
; By using rgnBBox as our source/destination rectangle, we make PPToPort do
; as little work as possible; There won't be anything to update outside of
; that rectangle.
;
	ldy #oVisRgn+2	; Find the visible rectangle.
	lda [deref],y	; First get the handle to the visRgn.
	sta Temp2+2
	dey
	dey
	lda [deref],y
	sta Temp2

	ldy #2	; deref the VisRgn handle
	lda [Temp2],y
	sta Temp1+2
	lda [Temp2]
	sta Temp1

	ldy #8	; finally copy the rect out of the
loop	lda [Temp1],y	; VisRgn into a local variable.
	sta VisRect-2,y
	dey
	dey
	bne loop

;
; VisRect now holds the rectangle that surrounds the entire area to udpate.
; This makes that "PushLong #VisRect" above point to valid data!
;
; Now we push on the destination for the PPToPort command. Since PPToPort
; doesn't do any scaling, all we need is the upper-left hand point of the
; destination; the lower left corner is calculated by QuickDraw by using the
; height and width of the source.

	PushLong VisRect	; use the upper left hand corner of the
		; source rectangle as the destination.

	PushWord #modeCopy	; Set the transfer mode.
	_PPToPort	; Blit those bits!!!

	pha	; push on room for GetWRefcon result
	pha
	PushLong oldPort
	_GetWRefCon
	_HUnlock	; unlock the Cache record handle

done
	plb	; restore caller's data bank register
	pld	; restore caller's direct page reg.

	rtl	; return to TaskMaster

oldPort	ds.b 4
VisRect	ds.b 8

	ENDP

	EJECT
*******************************************************************************
*
SlowDraw	PROC
*
* Description:	This routine calls the routine that draws the test window
*	contents. It takes the place of the 'CacheContents'
*	routine for Windows 1 and 2. It does NOT cache the window
*	contents, and is used to show the difference between
*	cached and non-cached updating.
*
*
* Inputs:
*
* Outputs:
*
* External Refs:
	import DrawContent
*
* Entry Points:
*
*******************************************************************************
	with Globals

;
; SlowDraw is called from the Window Manager to update the contents
; of the window. Therefore, the Direct Page and Data Bank Register may
; not be set to what our application had them set to. Save the settings
; as the Window Manager had them, and then set them up the way we like
; them. That way we can use local (2-byte absolute) addressing, and can
; access our Direct Page variables.
;
	phd
	phb

	phk
	plb
	lda MyDP
	tcd

	pha
	pha
	_GetPort
	pla
	plx

	jsl DrawContent

	plb
	pld

	rtl
	ENDP

	EJECT
*******************************************************************************
*
DrawByHand	PROC
*
* Description:	The contents need to be created for the first time. The
*	address of theroutine that doesthis is in a parameter
*	block pointed to by the RefCon. Get this address, push it
*	on the stack, and load up A and X with the pointer to the
*	window so that the drawing routine can have information
*	about it (the actual port it is drawing to is an offscreen
*	port, and does not have window information in it, like the
*	window title).
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import oldPort
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

	ldy #1	; Get bytes 1 and 2 of drawing routine.
	PushWord [CPPtr],y	; push bytes 1 and 2 on.
	phb	; push one byte onto the stack.
	lda [CPPtr]	; Get bytes 0 and 1 into Acc.
	sta 1,s	; now store bytes 0 and 1 on the stack
	lda oldPort	; set up A & X for the drawing routine
	ldx oldPort+2
	rtl	; RTL to the drawing routine

	ENDP

	EJECT
*******************************************************************************
*
DrawOdyRtn	PROC
*
* Description:	This routine posts the first few pages of Sculley's book
*	into the Cache buffer or onto the screen. It uses TextBox2
*	and takes a while, so tell the user by showing a watch.
*
*	None of what I do here requires the use of my Direct Page
*	or 2-byte absolute addressing, so I don't need to change
*	the Direct Page or Data Bank Registers. However, other
*	routines that perform updating will normally need to change
*	these. The CacheContents routine demonstrates the
*	technique.
*
*
* Inputs:	A = low order word of window pointer
*	X = high order word
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

;
; --- We'll be sitting here for a while, so tell the user.
;
	_WaitCursor

	PushLong #Odyssey	; push pointer to text
	PushWord #OdysseyEnd-Odyssey	; length of text
	PushLong #OdyRect	; bounds to fit the text into
	PushWord #0	; Fill justify
	_LETextBox2	; draw it all!

	_InitCursor	; set cursor back to arrow.

	rtl	; back to caller.

OdyRect	dc.w 0,10,790,590

	ENDP

	EJECT
*******************************************************************************
*
DrawContent	PROC
*
* Description:	This is the real procedure that draws the contents of the
*	Test windows. It merely draws the name of the window many
*	times.
*
*
* Inputs:	A = low order word of window pointer
*	X = high order word
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

	sta myPort	; save window pointer
	stx myPort+2

	pha	; room for window title pointer
	pha
	phx	; push on window pointer
	pha
	_GetWTitle	; get the window's title
	PullLong wTitle

	lda #10	; now initialize the X and Y variables
	sta yLoc	; that we use to draw the strings.
	lda #0
	sta xLoc
	lda #10	; loop 10 times down the screen
	sta bigCounter
loop
	PushWord xLoc	; set up for the Moveto
	PushWord yLoc
	_MoveTo

	lda #8	; loop 8 times across the screen
	sta littleCounter
loop2
	PushLong wTitle	; put window title pointer onto stack
	_DrawString	; and draw the string
	dec littleCounter	; update our horizontal counter
	bpl loop2

	lda yLoc	; update the X/Y coordinates
	clc
	adc #10
	sta yLoc
	lda xLoc
	sec
	sbc #20
	sta xLoc
	dec BigCounter	; update our vertical counter
	bpl loop	; ...and check it.

	rtl

xLoc	ds.b 2	; where to start drawing string next
yLoc	ds.b 2	; where to start drawing string next
littleCounter	ds.b 2	; counter across the screen
bigcounter	ds.b 2	; counter down the screen

myPort	ds.b 4
wTitle	ds.b 4

	ENDP

	EJECT
*******************************************************************************
*
GetOffScreenBuffer	PROC
*
* Description:	Get a handle to an offscreen GrafPort. If _NewHandle call
*	fails, set the carry and return. If it succeeds, create a
*	new bitmap for it, install the bitmap, and initialize the
*	appropriate fields. Finally, install the pointer to the
*	GrafPort in the cache record for the window, clear the
*	carry, and return with the port set to the new port.
*
*	This routine is entered with the pointer to the window
*	manager port of the window we are updating. In case we
*	cannot get an offscreen buffer, we can reset the port to
*	this.
*
*
* Inputs:	A = low word of window pointer of window we are updating
*	X = high word
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

	sta origPort	; save the window manager port
	stx origPort+2

;
; --- Get a memory for a new grafport
;
	stz newPort	; assume that we don't get it.
	stz newPort+2
	pha	; space for the new handle
	pha
	PushLong #portSize
	PushWord MyID
	PushWord #attrFixed	; plus 'attrNoCross' if on old ROMs
	PushLong #$0000
	_NewHandle
	PullLong deref
	bcs error

	ldy #2	; Dereference and lose the handle
	lda [deref],y	; (we only need a pointer)
	tax
	lda [deref]
	sta newPort
	stx newPort+2

	phx	; Now initialize it as a GrafPort
	pha
	_OpenPort
	bcs error
;
; --- We now have a port to play with, but its PixImage is the
; --- screen. Let's change that.
;
	jsr AddPixMap
	bcs error

; Everything is all set up. The current port should still be the one
; we just created with the _OpenPort above. All we have to do is install
; the pointer to it into the cacheParms block for the Window.

	ldy #4
	lda newPort
	sta [CPPtr],y
	iny
	iny
	lda newPort+2
	sta [CPPtr],y

	clc
	rts
error
	pha	; Error occured. Get the handle to the
	pha	; port that we created; dispose of it.
	PushLong newPort
	_FindHandle
	bcs skip
	_DisposeHandle
skip
	PushLong origPort
	_SetPort
	sec
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This routine adds an offscreen PixMap to the Grafport pointed to by
; 'newPort'.
;
AddPixMap
	jsr CalcScrnDims	; get values for LocInfo

	pha	; get a PixImagePtr of right size
	pha
	PushLong scrnSize
	PushWord MyID
	PushWord #attrFixed	; plus 'attrNoCross' if on old ROMs
	PushLong #$0000
	_NewHandle
	PullLong Deref
	bcs error2

;
; Get the Window Pointer into a Direct Page location (Temp1) for
; easy access later.
;
	lda newPort
	sta Temp1
	lda newPort+2
	sta Temp1+2

	ldy #2	; Dereference and lose the handle
	lda [deref],y	; to the PixImage (it's locked)
	tax
	lda [deref]	; (pointer in A and X)

	ldy #optrToPixImage	; install the new PixImage
	sta [Temp1],y
	iny
	iny
	txa
	sta [Temp1],y

	ldy #owidth	; set the 'rowBytes' value
	lda rowBytes
	sta [Temp1],y

	ldy #oboundsRect+4	; update the size of the boundsRect
	lda scrnHeight
	sta [Temp1],y
	iny
	iny
	lda scrnWidth
	sta [Temp1],y

	ldy #oPortRect+4	; and the size of the portrect
	lda scrnHeight
	sta [Temp1],y
	iny
	iny
	lda scrnWidth
	sta [Temp1],y

;
; Set the VisRgn and ClipRgn to the size of the port we just
; created. This is done by calling ClipRect with the portRect,
; and then copying the resulting ClipRgn to the VisRgn.
;
	lda Temp1	; Create a pointer to the portRect
	clc	; in the Window Record (remember,
	adc #oPortRect	; Temp1 points to the WindRec).
	tax
	lda Temp1+2
	adc #0
	pha	; push on one set for _EraseRect
	phx
	pha	; push on this set for _ClipRect
	phx
	_ClipRect

	ldy #oClipRgn+2	; now copy the ClipRgn to the VisRgn
	PushWord [Temp1],y
	dey
	dey
	PushWord [Temp1],y
	_SetVisRgn

	_EraseRect	; rect ptr left on from way before.

	clc
	rts

Error2
	sec
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Calculate the screen size based on the general formula:
;
;    rowbytes := (((((right - left) * theDepth) + 7) DIV 8) + 7) AND ~%111
;
; in English, or what passes for it when I type, this says: take the width
; of the GrafPort, and multiply it by the depth (number of bits per pixel)
; of the screen. Add 7 to this and divide by 8 to get the number of bytes
; that this takes up (add 7 effectively rounds up, to counter the DIV 8's
; rounding down). After we have the number of bytes, we have to make sure that
; this is an "even multiple of 8", as it states in the QuickDraw Chapter. This
; is done by adding 7 (again, to round up) and stripping off the low 3 bits,
; which performs the rounding down to the nearest multiple of 8.
;
; This formula can be slightly reduced to:
;
;    rowbytes := ((((right - left) * theDepth) + 63) DIV 8) AND ~%111
;
; which is used in specific:
;
;    rowBytes := (((scrnWidth * 2) + 63) DIV 8) AND ~%111
;
CalcScrnDims
	ldy #10	; get the screen width from cacheParms
	lda [CPPtr],y
	sta scrnWidth
	asl a	; times 2
;	asl a	; use this also if in 320 mode
	clc	; add 63
	adc #63
	lsr a	; divide by 8
	lsr a
	lsr a
	and #%11111000	; and with ~%111
	sta rowbytes
	pha	; Now prepare to multiply to get
	pha	; the whole screen size.
	pha	; Multiplier
	dey
	dey
	lda [CPPtr],y
	sta scrnHeight
	pha	; Multiplicand
	_Multiply
	PullLong ScrnSize
	rts

origPort	ds.b 4
newPort	ds.b 4

scrnSize	ds.b 4
scrnHeight	ds.b 2
scrnWidth	ds.b 2
rowBytes	ds.b 2

	ENDP

	include 'Jiffy.stds.aii'

	END

